home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 98
/
Skunkware 98.iso
/
src
/
interp
/
tclStruct1.2.tar.gz
/
tclStruct1.2.tar
/
tclStruct1.2
/
stTypes.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-09-12
|
11KB
|
389 lines
/*
* tclStruct package
* Support 'C' structures in Tcl
*
* Written by Matthew Costello
* (c) 1995 AT&T Global Information Solutions, Dayton Ohio USA
*
* See the file "license.terms" for information on usage and
* redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include "stInternal.h"
STRUCT_SCCSID("@(#)tclStruct:stTypes.c 1.2 95/09/12")
/*******************************************************************/
#ifdef DEBUG
CONST char *
Struct_TypeName(type)
Struct_TypeDef *type;
{
static char namebuf[128];
if (type->name != NULL)
sprintf(namebuf,"%.32s(r=%d, s=%d, f=%03o%s, t=%p)",
type->name,
type->refcount,
type->size,
type->flags,
(type->flags & STRUCT_FLAG_IS_ARRAY) ? " A" :
(type->flags & STRUCT_FLAG_IS_STRUCT) ? " S" :
(type->flags & STRUCT_FLAG_IS_POINTER) ? " P" : "",
(void *)type->TraceProc );
else
sprintf(namebuf,"anon%p(r=%d, s=%d, f=%03o%s, t=%p)",
(void *)type,
type->refcount,
type->size,
type->flags,
(type->flags & STRUCT_FLAG_IS_ARRAY) ? " A" :
(type->flags & STRUCT_FLAG_IS_STRUCT) ? " S" :
(type->flags & STRUCT_FLAG_IS_POINTER) ? " P" : "",
(void *)type->TraceProc );
return namebuf;
}
#endif
/* Create a new type. This type may, or may not, be registered
* with a name. We use anonymous types for arrays.
* ALL types are created here.
*/
/*ARGSUSED*/
Struct_TypeDef *
Struct_NewType( cdata, interp, typename, size, flags, traceProc )
ClientData cdata;
Tcl_Interp *interp;
CONST char *typename;
int size;
int flags;
Tcl_VarTraceProc *traceProc;
{
Struct_TypeDef *type;
#ifdef DEBUG
if (struct_debug & DBG_NEWTYPE)
printf("Struct_NewType( name = \"%s\", size = %d, flags = %03o, trace = %p\n",
typename ? typename : "<none>", size, flags, (void *)traceProc );
#endif
type = (Struct_TypeDef *)ckalloc(sizeof(Struct_TypeDef));
if (type == NULL) {
if (interp != NULL)
Tcl_SetResult(interp,"Can't allocate type structure object!",TCL_STATIC);
return NULL;
}
Struct_PkgInfo(cdata,si_nNewTypes) += 1;
memset( (char *)type, 0x00, sizeof(Struct_TypeDef) );
#ifdef STRUCT_MAGIC
type->magic = STRUCT_MAGIC_TYPE;
#endif
if (typename != NULL)
type->name = strdup( typename );
type->refcount = 1;
type->size = size;
type->flags = flags;
if (type->flags & STRUCT_FLAG_ALIGN_SIZE)
type->align = size;
else
type->align = 1;
type->TraceProc = traceProc;
#ifdef DEBUG
if (struct_debug & (DBG_NEWTYPE|DBG_REFCOUNT))
printf("Struct_NewType() = %p %s\n", (void *)type, Struct_TypeName(type) );
#endif
return type;
}
Struct_TypeDef *
Struct_CloneType( cdata, interp, typename, type )
ClientData cdata;
Tcl_Interp *interp;
CONST char *typename;
Struct_TypeDef *type;
{
Struct_TypeDef *newtype;
unsigned int size;
Struct_StructElem *pelem;
Struct_CheckType(type,"CloneType");
#ifdef DEBUG
if (struct_debug & (DBG_NEWTYPE))
printf("Struct_CloneType: cloning %s\n", Struct_TypeName(type) );
#endif
newtype = Struct_NewType( cdata, interp, typename,
type->size, type->flags, type->TraceProc );
if (type->fill != NULL)
newtype->fill = strdup(type->fill);
newtype->align = type->align;
switch (type->flags & STRUCT_FLAG_IS_MASK) {
case STRUCT_FLAG_IS_STRUCT:
/* Need to copy the list of structures as well. */
#ifdef DEBUG
if (struct_debug & (DBG_NEWTYPE))
printf("Struct_CloneType: structure has %d members\n",
type->u.s.num_elements );
#endif
size = (type->u.s.num_elements + 1) * sizeof(Struct_StructElem);
if ((newtype->u.s.struct_def = (Struct_StructElem *)ckalloc(size)) == NULL) {
Tcl_SetResult(interp,"Can't allocate structure member definition!",TCL_STATIC);
return NULL;
}
memcpy( (char *)newtype->u.s.struct_def,
(char *)type->u.s.struct_def, size );
newtype->u.s.num_elements = type->u.s.num_elements;
for ( pelem = newtype->u.s.struct_def; pelem->type != NULL; pelem++ ) {
Struct_AttachType( pelem->type );
if (pelem->name)
pelem->name = strdup(pelem->name);
}
break;
case STRUCT_FLAG_IS_ARRAY:
case STRUCT_FLAG_IS_POINTER:
case STRUCT_FLAG_IS_ADDR:
newtype->u.a.array_elem = type->u.a.array_elem;
Struct_AttachType( newtype->u.a.array_elem );
break;
}
Struct_ReleaseType(type);
return newtype;
}
Struct_TypeDef *
Struct_DefArray(cdata, interp, elemtype, nelem)
ClientData cdata;
Tcl_Interp *interp;
Struct_TypeDef *elemtype;
int nelem;
{
Struct_TypeDef *type;
int size;
int flags;
Struct_CheckType(elemtype,"DefArray");
#ifdef DEBUG
if (struct_debug & (DBG_NEWTYPE))
printf("Struct_DefArray( elem = %s, nelem = %d )\n",
Struct_TypeName(elemtype), nelem );
#endif
if (nelem < 0) {
Tcl_ResetResult(interp);
sprintf(interp->result,"negative array size of %d is illegal",nelem);
return NULL;
}
size = nelem * elemtype->size;
if (nelem == 0)
flags = STRUCT_FLAG_IS_ARRAY|STRUCT_FLAG_USE_STRICT|STRUCT_FLAG_VARLEN;
else
flags = STRUCT_FLAG_IS_ARRAY|STRUCT_FLAG_USE_STRICT|STRUCT_FLAG_STRICT;
if ((type = Struct_NewType( cdata, interp, (char *)NULL, size,
flags, NULL )) == NULL)
return NULL;
Struct_AttachType(elemtype);
type->u.a.array_elem = elemtype;
type->align = elemtype->align;
if (elemtype->flags & STRUCT_FLAG_TRACE_ARRAY) {
type->TraceProc = elemtype->TraceProc;
type->flags |= STRUCT_FLAG_TRACE_BASIC;
} else
type->TraceProc = Struct_TraceArray;
#ifdef DEBUG
if ( (struct_debug & (DBG_NEWTYPE)) ||
((nelem == 0) && (struct_debug & DBG_VARLEN)) )
printf("Struct_DefArray() = %p %s\n", (void *)type, Struct_TypeName(type) );
#endif
return type;
}
Struct_TypeDef *
Struct_InstantiateType(cdata, interp, typename, basetype, nelem )
ClientData cdata;
Tcl_Interp *interp;
CONST char *typename;
Struct_TypeDef *basetype;
int nelem;
{
Struct_TypeDef *type;
unsigned long oldsize;
Struct_CheckType(basetype,"InstantiateType");
#ifdef DEBUG
if (struct_debug & (DBG_VARLEN))
printf("Struct_InstantiateType( typename = %s, basetype = %s, nelem = %d )\n",
typename ? typename : "<none>", Struct_TypeName(basetype), nelem );
#endif
if (!(basetype->flags & STRUCT_FLAG_VARLEN)) {
Tcl_AppendResult(interp,"not a variable type",
(char *)NULL );
return NULL;
}
type = Struct_CloneType(cdata, interp, (char *)typename, basetype );
/* Struct_ReleaseType(basetype); */
if (type == NULL) {
return NULL;
}
type->flags &= ~STRUCT_FLAG_VARLEN;
switch (type->flags & STRUCT_FLAG_IS_MASK) {
case STRUCT_FLAG_IS_ARRAY:
type->flags |= STRUCT_FLAG_STRICT;
type->size = nelem * type->u.a.array_elem->size;
break;
case STRUCT_FLAG_IS_STRUCT:
oldsize = type->u.s.struct_def[type->u.s.num_elements - 1].type->size;
type->u.s.struct_def[type->u.s.num_elements - 1].type =
Struct_InstantiateType(cdata,interp,NULL,
type->u.s.struct_def[type->u.s.num_elements - 1].type,nelem);
type->size += (type->u.s.struct_def[type->u.s.num_elements - 1].type->size - oldsize);
break;
default:
Tcl_AppendResult(interp,"Struct_InstantiateType:: not a variable type",
(char *)NULL );
return NULL;
}
/* Make sure the object has a size that is a multiple of the alignment.
*/
type->size = (type->size + type->align - 1) / type->align;
type->size *= type->align;
#ifdef DEBUG
if (struct_debug & (DBG_VARLEN))
printf("Struct_InstantiateType() = %s\n", Struct_TypeName(type) );
#endif
return type;
}
/* Register a new type.
* Both simple types (e.g. "int") and structures
* are defined here.
*/
int
Struct_RegisterType(cdata, interp, typename, type)
ClientData cdata;
Tcl_Interp *interp;
CONST char *typename;
Struct_TypeDef *type;
{
Tcl_HashEntry *entryPtr;
int new;
if (typename == NULL)
return TCL_OK;
if (type == NULL) {
Tcl_AppendResult(interp,"null type for \"",typename,"\"",
(char *)NULL );
return TCL_ERROR;
}
Struct_CheckType(type,"RegisterType");
entryPtr=Tcl_CreateHashEntry(Struct_TypeHash(cdata),(char *)typename,&new);
if (!new) {
Tcl_AppendResult(interp,"name \"",typename,"\" already allocated",
(char *)NULL );
return TCL_ERROR;
}
Struct_AttachType(type); /* It should stay around forever */
if (type->name == NULL)
type->name = strdup( typename );
Tcl_SetHashValue(entryPtr,type);
return TCL_OK;
}
int
Struct_RegisterBuiltInType(cdata, interp, typename, size,flags,traceProc)
ClientData cdata;
Tcl_Interp *interp;
CONST char *typename;
int size;
int flags;
Tcl_VarTraceProc *traceProc;
{
Struct_TypeDef *type;
if ((type = Struct_NewType(cdata,interp,typename,size,
flags|STRUCT_FLAG_BUILTIN|STRUCT_FLAG_TRACE_BASIC,
traceProc)) == NULL)
return TCL_ERROR;
if (Struct_RegisterType(cdata,interp,typename,type) == TCL_ERROR) {
Struct_ReleaseType(type);
return TCL_ERROR;
}
return TCL_OK;
}
/*
* Struct_AttachType
* Struct_ReleaseType
*
* Attach a type by incrementing its reference count.
* Release a type by decrementing its reference count.
*
* This is done so that types may be freed up when the
* last reference to a type has gone. The built-in
* types have a reference count of two (2) to prevent
* them from being untypedef'd.
*
* When a type's reference count goes to zero it is freed
* up after first decrementing the reference counts of
* any types that it references.
*/
void
Struct_AttachType(type)
Struct_TypeDef *type;
{
if (type == NULL)
return;
Struct_CheckType(type,"AttachType");
#ifdef DEBUG
if (struct_debug & (DBG_REFCOUNT))
printf("Struct_AttachType: attaching %s\n", Struct_TypeName(type) );
#endif
type->refcount++;
}
void
Struct_ReleaseType(type)
Struct_TypeDef *type;
{
Struct_StructElem *pelem;
if (type == NULL)
return;
Struct_CheckType(type,"ReleaseType");
if (--type->refcount > 0) {
#ifdef DEBUG
if (struct_debug & (DBG_REFCOUNT))
printf("Struct_ReleaseType: keeping %s\n", Struct_TypeName(type) );
#endif
return;
}
#ifdef DEBUG
if (type->refcount < 0)
panic("ERROR: negative type refcount on %s\n", Struct_TypeName(type) );
if (struct_debug & (DBG_REFCOUNT|DBG_NEWTYPE))
printf("Struct_ReleaseType: freeing %s\n", Struct_TypeName(type) );
#endif
#ifdef ACCESS_TO_INTERPRETER
Struct_PkgInfo(cdata,si_nExTypes) += 1;
#endif
/* Special processing for different kinds of types */
switch (type->flags & STRUCT_FLAG_IS_MASK) {
case STRUCT_FLAG_IS_ARRAY:
case STRUCT_FLAG_IS_POINTER:
case STRUCT_FLAG_IS_ADDR:
if (!(type->flags & STRUCT_FLAG_RECURSIVE))
Struct_ReleaseType( type->u.a.array_elem );
break;
case STRUCT_FLAG_IS_STRUCT:
for ( pelem = type->u.s.struct_def; pelem->type != NULL; pelem++ ) {
#ifndef STRUCT_NOFREE
if (pelem->name != NULL)
ckfree( pelem->name );
#endif
Struct_ReleaseType( pelem->type );
}
#ifndef STRUCT_NOFREE
ckfree( type->u.s.struct_def );
#endif
}
#ifndef STRUCT_NOFREE
ckfree( type );
#endif
}